<?php
/**
 * Unit Tests for OAuth_Uri
 * 
 * @package OAuth
 * @copyright Luke Visinoni (luke.visinoni@gmail.com)
 * @author Luke Visinoni (luke.visinoni@gmail.com)
 * @license GNU Lesser General Public License
 */
class UnitTestCase_OAuth_Uri extends UnitTestCase {

    public function setUp() {
    
        // set up test env...
    
    }
    
    public function tearDown() {
    
        // tear down test env...
    
    }
    
    public function testConstructUriWithSchemeAndHost() {
    
        $uri = new OAuth_Uri('http', 'www.example.com');
        $this->assertEqual($uri->getScheme(), 'http');
        $this->assertEqual($uri->getHostName(), 'www.example.com');
    
    }
    
    public function testSetSchemeToSecure() {
    
        $uri = new OAuth_Uri('https', 'www.example.com');
        $this->assertEqual($uri->getScheme(), 'https');
    
    }
    
    public function testToString() {
    
        $uri = new OAuth_Uri('http', 'www.example.com');
        $this->assertEqual($uri->__toString(), 'http://www.example.com');
    
    }
    
    public function testConstructUriWithPath() {
    
        $uri = new OAuth_Uri('http', 'www.example.com', 'path/to');
        $this->assertEqual($uri->getPath(), 'path/to');
        $this->assertEqual($uri->__toString(), 'http://www.example.com/path/to');
        $uri->setPath('/boo/barbaz/');
        $this->assertEqual($uri->getPath(), '/boo/barbaz/');
        $this->assertEqual($uri->__toString(), 'http://www.example.com/boo/barbaz/');
    
    }
    
    /**
     * @todo I'm not sure if there should just ALWAYS be a slash added
     */
    public function testSlashIsNotAddedIfNoPathIsPassedIn() {
    
        $uri = new OAuth_Uri('http', 'www.example.com');
        $this->assertEqual($uri->__toString(), 'http://www.example.com');
        $uri = new OAuth_Uri('http', 'www.example.com/');
        $this->assertEqual($uri->__toString(), 'http://www.example.com/');
        $uri = new OAuth_Uri('http', 'www.example.com', null, array('foo' => 'boo'));
        $this->assertEqual($uri->__toString(), 'http://www.example.com?foo=boo');
        $uri = new OAuth_Uri('http', 'www.example.com', '/', array('foo' => 'boo'));
        $this->assertEqual($uri->__toString(), 'http://www.example.com/?foo=boo');
    
    }
    
    public function testConstructUriWithPathWithExtension() {
    
        $uri = new OAuth_Uri('http', 'www.example.com', 'path/to/file.html');
        $this->assertEqual($uri->__toString(), 'http://www.example.com/path/to/file.html');
    
    }
    
    public function testSetPort() {
    
        $uri = new OAuth_Uri('http', 'example.com', 'path', null, 8443);
        $this->assertEqual($uri->getPort(), 8443);
        $this->assertEqual($uri->__toString(), 'http://example.com:8443/path');
    
    }
    
    public function testDefaultPortDoesntShowUpInUrl() {

        // default port for http is 80    
        $uri = new OAuth_Uri('http', 'example.com', 'foo/bar', 'foo=bar', 80);
        $this->assertEqual($uri->__toString(), 'http://example.com/foo/bar?foo=bar');
        $uri->setPort(8443);
        $this->assertEqual($uri->__toString(), 'http://example.com:8443/foo/bar?foo=bar');
        
        // default port for https is 443
        $uri = new OAuth_Uri('https', 'example.com', 'foo/bar', 'foo=bar', 443);
        $this->assertEqual($uri->__toString(), 'https://example.com/foo/bar?foo=bar');
        $uri->setPort(8443);
        $this->assertEqual($uri->__toString(), 'https://example.com:8443/foo/bar?foo=bar');
    
    }
    
    public function testPortDefaultsBasedOnScheme() {
    
        $uri = new OAuth_Uri('http');
        $this->assertEqual($uri->getPort(), 80);
        $uri = new OAuth_Uri('https');
        $this->assertEqual($uri->getPort(), 443);
    
    }
    
    public function testPathInfo() {
    
        $uri = new OAuth_Uri('http', 'example.com', 'foo/index.php', '?foo=boo&bar=far', null, '/path/info');
        $this->assertEqual($uri->getPathInfo(), '/path/info');
    
    }
    
    public function testGetAndSetQueryParams() {
    
        $params = array('foo' => 'bar', 'boo' => 'far');
        $uri = new OAuth_Uri('http', 'www.example.com', '/path/to/file', $params);
        $this->assertEqual($uri->getParams(), $params);
    
    }
    
    public function testGetAndSetSingleParam() {
    
        // test setting single param when no params are already set
        $uri = new OAuth_Uri('http', 'www.example.com');
        $uri->setParam('foo', 'bar');
        $this->assertEqual($uri->getParam('foo'), 'bar');
        
        // test setting single param when params are already set (but not the one we're setting)
        $uri = new OAuth_Uri('http', 'www.example.com', null, array('foo' => 'bar'));
        $uri->setParam('boo', 'far');
        $this->assertEqual($uri->getParam('foo'), 'bar');
        $this->assertEqual($uri->getParam('boo'), 'far');
        
        // test setting single param (overwriting an existing one)
        $uri->setParam('foo', 'far');
        $this->assertEqual($uri->getParam('foo'), 'far');
    
    }
    
    public function testGetNonexistentParam() {
    
        $uri = new OAuth_Uri('http', 'www.example.com', '/', array('foo' => 'bar'));
        $this->expectException(new OAuth_Uri_Exception_ParamNotExist("The param you have requested does not exist: 'boo'"));
        $boo = $uri->getParam('boo');
    
    }
    
    public function testSetParamsAsString() {
    
        $params = array('foo' => 'bar', 'boo' => 'far');
        $uri = new OAuth_Uri('http', 'www.example.com', 'path/to/file', 'foo=bar&boo=far');
        $this->assertEqual($uri->getParams(), $params);
    
    }
    
    public function testSetParamAsStringWithBadString() {
    
        $params = array('foo' => 'bar', 'boo' => 'far');
        $uri = new OAuth_Uri('http', 'www.example.com', 'path/to/file.html', 'foobar&loobar&choobar&thisiscool&&&&');
        $this->assertEqual($uri->getParams(), array('foobar' => null, 'loobar' => null, 'choobar' => null, 'thisiscool' => null));
    
    }
    
    /**
     * I'm not sure if invalid characters should be encoded during __toString()
     * or if they should be encoded when passed back from getParams()
     * I'll come back to this
     */
    /*public function testSetParamsEncodesInvalidCharacters() {
    
        $uri = new OAuth_Uri('http', 'www.example.com', 'foo.html', 'foo=th^s&bar=t#at&b*0=$hit&bl+t=bl@t&fl\p=f/op');
    
    }*/
    
    public function testToStringAfterSetParams() {
    
        $uri = new OAuth_Uri('http', 'www.example.com', 'foo.html');
        $uri->setParams(array('foo' => 'bar', 'boo' => 'far'));
        $this->assertEqual($uri->__toString(), 'http://www.example.com/foo.html?foo=bar&boo=far');
    
    }
    
    public function testConstructWithNullPath() {
    
        $uri = new OAuth_Uri('http', 'www.example.com', null, array('foo' => 'bar'));
        $this->assertEqual($uri->__toString(), 'http://www.example.com?foo=bar');
    
    }
    
    public function testParamsWithoutValues() {
    
        $uri = new OAuth_Uri('http', 'example.com', null, array('foo' => null, 'bar' => 'boo', 'noo' => '', 'goo' => 'gar'));
        $this->assertEqual($uri->__toString(), 'http://example.com?foo&bar=boo&noo=&goo=gar');
    
    }
    
    public function testStringParamWithAndWithoutQuestionMark() {
    
        $uri = new OAuth_Uri('http', 'example.com', null, '?foo=bar&boo=far');
        $this->assertEqual($uri->__toString(), 'http://example.com?foo=bar&boo=far');
        $uri = new OAuth_Uri('http', 'example.com', null, 'foo=bar&boo=far');
        $this->assertEqual($uri->__toString(), 'http://example.com?foo=bar&boo=far');
    
    }
    
    public function testSetUser() {
    
        $uri  = new OAuth_Uri('http', 'www.example.com', 'path/to/file.html', 'foo=bar', null, null, null, 'luke');
        $this->assertEqual($uri->getUser(), 'luke');
        // @todo I don't think that user is allowed without password. Find out...
        $this->assertEqual($uri->__toString(), 'http://luke@www.example.com/path/to/file.html?foo=bar');
        $uri = new OAuth_Uri('http', 'www.example.com', 'path/to/file');
        $uri->setCredentials('luke');
        $this->assertEqual($uri->__toString(), 'http://luke@www.example.com/path/to/file');
    
    }
    
    public function testSetUserPassword() {
    
        $uri  = new OAuth_Uri('http', 'www.example.com', 'path/to/file.html', 'foo=bar', null, null, null, 'luke', 'foobar');
        $this->assertEqual($uri->getUser(), 'luke');
        $this->assertEqual($uri->getPassword(), 'foobar');
        $this->assertEqual($uri->__toString(), 'http://luke:foobar@www.example.com/path/to/file.html?foo=bar');
        $uri = new OAuth_Uri('http', 'www.example.com', 'path/to/file');
        $uri->setCredentials('luke', 'foobar');
        $this->assertEqual($uri->__toString(), 'http://luke:foobar@www.example.com/path/to/file');
    
    }
    
    public function testParseUrlStaticMethod() {
    
        $expected_keys = array('scheme', 'host', 'port', 'user', 'pass', 'path', 'query', 'fragment');
        $parseurl = OAuth_Uri::parse_url('http://user:pass@www.example.com:8443/path/to/file.php/fileinfo/path/?query=values&foo=bar#frag');
        $this->assertEqual(array_keys($parseurl), $expected_keys);
        $this->assertEqual($parseurl, array(
            'scheme' => 'http',
            'host' => 'www.example.com',
            'port' => 8443,
            'user' => 'user',
            'pass' => 'pass',
            'path' => '/path/to/file.php/fileinfo/path/',
            'query' => 'query=values&foo=bar',
            'fragment' => 'frag',
        ));
        
        // make sure it works with minimal URIs as well...
        $parseurl = OAuth_Uri::parse_url('http://www.example.com/');
        $this->assertEqual(array_keys($parseurl), $expected_keys);
        $this->assertEqual($parseurl, array(
            'scheme' => 'http',
            'host' => 'www.example.com',
            'port' => null,
            'user' => null,
            'pass' => null,
            'path' => '/',
            'query' => null,
            'fragment' => null,
        ));
    
    }
    
    /**
     * This is actually done in the factory method now...
     */
    public function testPassArrayToFactory() {
    
        $uri = OAuth_Uri::factory(array(
            'scheme' => 'http',
            'host' => 'www.example.com',
        ));
        $this->assertEqual($uri->__toString(), 'http://www.example.com');
        $this->assertEqual($uri->getHostName(), 'www.example.com');
        $this->assertEqual($uri->getScheme(), 'http');
    
    }
    
    public function testFactory() {
    
        // test a URI with "the works"
        $uri = OAuth_Uri::factory("http://user:pass@www.example.com:8443/foo/bar/index.php/pathinfo/foo/?foo=bar&boo=far&bar=foo&far=foo");
        $this->assertEqual($uri->getScheme(), 'http');
        $this->assertEqual($uri->getUser(), 'user');
        $this->assertEqual($uri->getPassword(), 'pass');
        $this->assertEqual($uri->getHostName(), 'www.example.com');
        $this->assertEqual($uri->getPort(), 8443);
        $this->assertEqual($uri->getPath(), 'foo/bar/index.php');
        $this->assertEqual($uri->getPathInfo(), '/pathinfo/foo/');
        $this->assertEqual($uri->getParams(), array('foo' => 'bar', 'boo' => 'far', 'bar' => 'foo', 'far' => 'foo'));
        
        // test a URI with only a few of the possible args
        $uri = OAuth_Uri::factory('http://www.example.com');
        $this->assertEqual($uri->getScheme(), 'http');
        $this->assertEqual($uri->getHostName(), 'www.example.com');
        $this->assertEqual($uri->__toString(), 'http://www.example.com');
    
    }
    
    /*
    public function testFactorySchemeDefaultsToHttp() {
    
        // coming soon...
    
    }
    
    // @todo move the array instantiation method into the factory instead
    public function testFactoryWithArray() {
    
        $uri = OAuth_Uri::factory();

    
    }
    */
    
    /*
    public function testSetOptions() {
    
        // I'm thinking maybe of allowing a sort of configuration options
        // array with things such as "append_slash", "encode_param_values", "encode_callback" and things like that.
    
    }
    */

}